home *** CD-ROM | disk | FTP | other *** search
- /* bzr_output.c: write a BZR-format font file.
-
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "config.h"
-
- #include "bzr.h"
- #include "file-output.h"
- #include "scaled-num.h"
- #include "spline.h"
-
- #include "bzr_opcodes.h"
- #include "bzr_types.h"
-
- /* Where the output will go. */
- static FILE *bzr_output_file = NULL;
- static string bzr_output_filename;
-
-
- /* We remember the design size, so we can scale by it. */
- static real design_size = 0.0;
-
-
- /* We keep track of the character locator information as we output
- characters, to save the caller from doing the bookkeeping. */
- static char_locator_type char_loc[MAX_CHARCODE + 1];
-
-
- /* The bounding box of all the characters we have written. The values
- here should be the largest and smallest possible numbers. */
- static real_bounding_box_type font_bb
- = { FLT_MAX, FLT_MIN, FLT_MAX, FLT_MIN };
-
-
- /* Low-level output. These macros call the corresponding lib routines
- with the static variables for the input file and filename. */
-
- #define BZR_FTELL() xftell (bzr_output_file, bzr_output_filename)
- #define BZR_PUT_BYTE(b) put_byte (b, bzr_output_file, bzr_output_filename)
- #define BZR_PUT_TWO(n) put_two (n, bzr_output_file, bzr_output_filename)
- #define BZR_PUT_FOUR(n) put_four (n, bzr_output_file, bzr_output_filename)
- #define BZR_PUT_N_BYTES(n, a) \
- put_n_bytes (n, a, bzr_output_file, bzr_output_filename);
-
-
- /* Determine whether the number N (in points) can be part of an abbrev
- command, i.e., its magnitude is less than half the design size. */
- #define MIN_ABBREV (-32768.0 / 65535.0)
- #define MAX_ABBREV (32767.0 / 65535.0)
- #define ABBREV_P(n) (MIN_ABBREV < (n) / design_size \
- && (n) / design_size < MAX_ABBREV)
-
- static void bzr_put_scaled (real);
- static void bzr_put_design_scaled (real);
- static void bzr_put_point (real_coordinate_type);
- static void bzr_put_abbrev_scaled (real);
- static void bzr_put_abbrev_design_scaled (real);
- static void bzr_put_abbrev_point (real_coordinate_type);
-
- /* Routines to start and end writing a file. (For the user to call.)
- We make sure the caller doesn't try to have two output files open
- simultaneously. */
-
- boolean
- bzr_open_output_file (string filename)
- {
- assert (bzr_output_file == NULL);
-
- bzr_output_filename = filename;
- bzr_output_file = fopen (filename, "w");
-
- if (bzr_output_file != NULL)
- {
- unsigned this_char;
-
- for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
- CHAR_POINTER (char_loc[this_char]) = NULL_BYTE_PTR;
- return true;
- }
- else
- return false;
- }
-
-
- void
- bzr_close_output_file ()
- {
- assert (bzr_output_file != NULL);
-
- xfclose (bzr_output_file, bzr_output_filename);
- bzr_output_filename = NULL;
- bzr_output_file = NULL;
- }
-
- /* The preamble. Since we are supposed to scale many numbers in the BZR
- file by the design size, we squirrel that value away. */
-
- void
- bzr_put_preamble (bzr_preamble_type p)
- {
- unsigned comment_length;
-
- assert (bzr_output_file != NULL);
-
- bzr_put_scaled (BZR_DESIGN_SIZE (p));
- design_size = BZR_DESIGN_SIZE (p);
-
- comment_length = strlen (BZR_COMMENT (p));
- if (comment_length > 255)
- {
- string comment = xmalloc (256);
-
- WARNING2 ("BZR comment `%s' too long (%u characters, which is > 255)",
- BZR_COMMENT (p), comment_length);
- /* We can't just put a null into BZR_COMMENT, since it might be in
- read-only storage. */
- comment_length = 255;
- strncpy (comment, BZR_COMMENT (p), comment_length);
- comment[comment_length] = 0;
- BZR_COMMENT (p) = comment;
- }
-
- BZR_PUT_BYTE (comment_length);
- BZR_PUT_N_BYTES (comment_length, BZR_COMMENT (p));
- }
-
- /* Characters. */
-
- /* Write the character C to `bzr_output_file' (which must already be
- open). It is a (non-fatal) error to try to write two characters with
- the same character code. */
-
- void
- bzr_put_char (bzr_char_type c)
- {
- unsigned this_list;
- void (*put_design_scaled) (real);
- void (*put_point) (real_coordinate_type);
- spline_list_array_type shape = BZR_SHAPE (c);
- char_locator_type *this_char_loc = &(char_loc[CHARCODE (c)]);
-
- assert (bzr_output_file != NULL);
-
- /* We should update the character locator information first, to be
- sure we don't try to output the same character twice. */
- if (CHAR_POINTER (*this_char_loc) != NULL_BYTE_PTR)
- {
- WARNING1 ("Attempt to output BZR character %u more than once; only \
- the first will be written", CHARCODE (c));
- return;
- }
-
- /* OK, this is a new character. Remember our current position, for
- writing the postamble. */
- CHAR_POINTER (*this_char_loc) = BZR_FTELL ();
-
- /* Now, on to the real business of outputting the character
- definition. If all numbers are small enough, we can use the
- abbreviated boc. */
- put_design_scaled
- = (ABBREV_P (CHAR_SET_WIDTH (c))
- && ABBREV_P (CHAR_MIN_COL (c)) && ABBREV_P (CHAR_MIN_ROW (c))
- && ABBREV_P (CHAR_MAX_COL (c)) && ABBREV_P (CHAR_MAX_ROW (c)))
- ? bzr_put_abbrev_design_scaled : bzr_put_design_scaled;
- BZR_PUT_BYTE (put_design_scaled == bzr_put_abbrev_design_scaled
- ? BOC_ABBREV : BOC);
- BZR_PUT_BYTE (CHARCODE (c));
- put_design_scaled (CHAR_SET_WIDTH (c));
-
- /* We believe the bounding box we are given, since to compute it
- ourselves would require rasterizing the splines, which should not
- be part of this routine. */
- put_design_scaled (CHAR_MIN_COL (c));
- put_design_scaled (CHAR_MIN_ROW (c));
- put_design_scaled (CHAR_MAX_COL (c));
- put_design_scaled (CHAR_MAX_ROW (c));
-
- /* Update the font bounding box. */
- if (CHAR_MIN_COL (c) < MIN_COL (font_bb))
- MIN_COL (font_bb) = CHAR_MIN_COL (c);
- if (CHAR_MAX_COL (c) > MAX_COL (font_bb))
- MAX_COL (font_bb) = CHAR_MAX_COL (c);
- if (CHAR_MIN_ROW (c) < MIN_ROW (font_bb))
- MIN_ROW (font_bb) = CHAR_MIN_ROW (c);
- if (CHAR_MAX_ROW (c) > MAX_ROW (font_bb))
- MAX_ROW (font_bb) = CHAR_MAX_ROW (c);
-
- for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
- this_list++)
- {
- unsigned this_spline;
- spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
- spline_type first_spline = SPLINE_LIST_ELT (list, 0);
-
- BZR_PUT_BYTE (START_PATH);
- bzr_put_point (START_POINT (first_spline));
-
- for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
- this_spline++)
- {
- spline_type s = SPLINE_LIST_ELT (list, this_spline);
-
- if (SPLINE_DEGREE (s) == LINEAR)
- {
- one_byte opcode;
- if (ABBREV_P (END_POINT (s).x) && ABBREV_P (END_POINT (s).y))
- {
- put_point = bzr_put_abbrev_point;
- opcode = LINE_ABBREV;
- }
- else
- {
- put_point = bzr_put_point;
- opcode = LINE;
- }
-
- BZR_PUT_BYTE (opcode);
- put_point (END_POINT (s));
- }
-
- else if (SPLINE_DEGREE (s) == CUBIC)
- {
- one_byte opcode;
-
- if (ABBREV_P (CONTROL1 (s).x) && ABBREV_P (CONTROL1 (s).y)
- && ABBREV_P (CONTROL2 (s).x) && ABBREV_P (CONTROL2 (s).y)
- && ABBREV_P (END_POINT (s).x) && ABBREV_P (END_POINT (s).y))
- {
- put_point = bzr_put_abbrev_point;
- opcode = SPLINE_ABBREV;
- }
- else
- {
- put_point = bzr_put_point;
- opcode = SPLINE;
- }
-
- BZR_PUT_BYTE (opcode);
- put_point (CONTROL1 (s));
- put_point (CONTROL2 (s));
- put_point (END_POINT (s));
- }
-
- else
- FATAL2 ("bzr_put_char: Spline #%d's degree was %d in out_splines",
- this_spline, SPLINE_DEGREE (s));
- }
- }
-
- BZR_PUT_BYTE (EOC);
- }
-
- /* The postamble. */
-
- void
- bzr_put_postamble ()
- {
- unsigned c;
- byte_count_type post_ptr;
- unsigned nchars = 0;
-
- assert (bzr_output_file != NULL);
-
- post_ptr = BZR_FTELL ();
- BZR_PUT_BYTE (POST);
-
- /* First comes the font bounding box. */
- bzr_put_design_scaled (MIN_COL (font_bb));
- bzr_put_design_scaled (MIN_ROW (font_bb));
- bzr_put_design_scaled (MAX_COL (font_bb));
- bzr_put_design_scaled (MAX_ROW (font_bb));
-
- /* Then the character locators. */
- for (c = 0; c <= MAX_CHARCODE; c++)
- {
- char_locator_type this_char_loc = char_loc[c];
-
- if (CHAR_POINTER (this_char_loc) != NULL_BYTE_PTR)
- {
- if (CHAR_POINTER (this_char_loc) < (1 << 16))
- {
- BZR_PUT_BYTE (CHAR_LOC_ABBREV);
- BZR_PUT_BYTE (c);
- BZR_PUT_TWO (CHAR_POINTER (this_char_loc));
- }
- else
- {
- BZR_PUT_BYTE (CHAR_LOC);
- BZR_PUT_BYTE (c);
- BZR_PUT_FOUR (CHAR_POINTER (this_char_loc));
- }
- nchars++;
- }
- }
-
- /* Then the number of characters. */
- BZR_PUT_BYTE (nchars);
-
- /* Now a pointer back to the postamble. */
- BZR_PUT_BYTE (POST_POST);
- BZR_PUT_FOUR (post_ptr);
- BZR_PUT_BYTE (BZR_ID);
- BZR_PUT_BYTE (NO_OP);
- }
-
- /* Low-level output routines. */
-
- static void
- bzr_put_scaled (real r)
- {
- scaled s;
-
- if (r >= 256.0)
- {
- WARNING1 ("bzr_put_scaled: Value too large to be output (%f)", r);
- r = 255.999;
- }
-
- s = real_to_scaled (r);
-
- BZR_PUT_BYTE ((s & 0xff0000) >> 16);
- BZR_PUT_BYTE ((s & 0xff00) >> 8);
- BZR_PUT_BYTE ((s & 0xff));
- }
-
-
- /* We have remembered the design size value from when we output the
- preamble. */
-
- static void
- bzr_put_design_scaled (real r)
- {
- bzr_put_scaled (r / design_size);
- }
-
-
- static void
- bzr_put_point (real_coordinate_type c)
- {
- bzr_put_design_scaled (c.x);
- bzr_put_design_scaled (c.y);
- }
-
-
- static void
- bzr_put_abbrev_scaled (real r)
- {
- scaled s;
-
- if (r > MAX_ABBREV || r <= MIN_ABBREV)
- {
- WARNING1 ("bzr_put_abbrev_scaled: Value too large to be output (%f)", r);
- r = MAX_ABBREV;
- }
-
- s = real_to_scaled (r);
-
- BZR_PUT_BYTE ((s & 0xff00) >> 8);
- BZR_PUT_BYTE ((s & 0xff));
- }
-
-
- /* We have remembered the design size value from when we output the
- preamble. */
-
- static void
- bzr_put_abbrev_design_scaled (real r)
- {
- bzr_put_abbrev_scaled (r / design_size);
- }
-
-
- static void
- bzr_put_abbrev_point (real_coordinate_type c)
- {
- bzr_put_abbrev_design_scaled (c.x);
- bzr_put_abbrev_design_scaled (c.y);
- }
-